#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#define SECONDS 1
#define MINUTES 60
#define HOURS (60 * MINUTES)
#define DAYS (24 * HOURS)
#define WEEKS (7 * DAYS)
#define MONTHS (DAYS * 30.4368499)
#define YEARS 31556926

#define TODAY time(NULL)
#define YESTERDAY TODAY-DAYS
#define LASTWEEK TODAY-WEEKS
#define LASTMONTH TODAY-MONTHS
#define LASTYEAR TODAY-YEARS

struct range {
  int nelems;
  time_t *elems;
};

time_t
date(const char *s)
{
  if (isdigit(s[0]))
    return atoi(s);
  if (strcmp(s, "today") == 0)
    return TODAY;
  if (strcmp(s, "yesterday") == 0)
    return YESTERDAY;
  if (strcmp(s, "lastweek") == 0)
    return LASTWEEK;
  if (strcmp(s, "lastmonth") == 0)
    return LASTMONTH;
  if (strcmp(s, "lastyear") == 0)
    return LASTYEAR;
  if (strcmp(s, "seconds") == 0)
    return SECONDS;
  if (strcmp(s, "hours") == 0)
    return HOURS;
  if (strcmp(s, "minutes") == 0)
    return MINUTES;
  if (strcmp(s, "days") == 0)
    return DAYS;
  if (strcmp(s, "weeks") == 0)
    return WEEKS;
  if (strcmp(s, "months") == 0)
    return MONTHS;
  if (strcmp(s, "years") == 0)
    return YEARS;
}

struct range *
new_range(time_t *elems, int nelems)
{
  struct range *r = malloc(sizeof(struct range));
  r->nelems = nelems;
  r->elems = elems;
  return r;
}

void
destroy_range(struct range *r)
{
  free(r->elems);
  free(r);
}

struct range *
timestamp_range(time_t begin, time_t end, time_t step)
{
  struct range *res = NULL;
  time_t *elems = NULL;
  time_t i, j;
  int size = end - begin;
  int n = size / step;
  assert(n >= 0);
  elems = malloc(sizeof(time_t) * n);
  for (i=0, j=begin; j <= end; i++, j += step)
    elems[i] = j;
  res = new_range(elems, n);
  return res;
}

int
main(int argc, char *argv[])
{
  time_t begin, end, step;
  int i;
  struct range *r = NULL;

  assert(argc > 2);
  begin =date(argv[1]);
  end = date(argv[2]);
  if (argc > 3)
    step = date(argv[3]);
  else
    step = MINUTES;
  r = timestamp_range(begin, end, step);
  for (i=0; i < r->nelems; i++)
    printf("%s", ctime(&r->elems[i]));
  destroy_range(r);
}

